#include "IXML.h"

#include "tinyxml2.h"
#include <vector>
#include <map>

class Tiny2Node : public INode{
public:
    Tiny2Node(tinyxml2::XMLElement *node) :_node(node)
    {
        name = node->Name();
        initAttrs();
    }
    Tiny2Node(){}
    /**
    * 平行节点的下一个节点
    */
    virtual INode* nextNode(const char *name)
    {
        return newNext(_node->NextSiblingElement(name));
    }
    /**
    * 获取节点属性
    */
    virtual std::string getStr(const char *name)
    {
        return (_node->Attribute(name) ? _node->Attribute(name):"");
    }

    /**
    * 获取子节点
    */
    virtual INode* childNode(const char *name)
    {
        const char *xxname = name;
        if (name == NULL) xxname = _node->FirstChildElement()->Name();
        return newName(xxname,_node->FirstChildElement(name));
    }

    private:
    tinyxml2::XMLElement *_node;
    std::string next;
    std::map<std::string,std::string> childs;
    friend class Tiny2Doc;

    Tiny2Node *newNext(tinyxml2::XMLElement *ele)
    {
        if (!ele) return 0;
        next.resize(sizeof(Tiny2Node) + sizeof(int));
        Tiny2Node * next1 = new (&next[0]) Tiny2Node(ele);
        return next1;
    }
    Tiny2Node *newName(const char *name,tinyxml2::XMLElement *ele)
    {
        if (!ele) return 0;
        std::string & child = childs[name];
        child.resize(sizeof(Tiny2Node) + sizeof(int));
        Tiny2Node * node = new (&child[0]) Tiny2Node(ele);
        return node;
    }
    void initAttrs(){
        auto attr = _node->FirstAttribute();
        while (attr) {
            attrs[attr->Name()] = attr->Value();
            attr = attr->Next();
        }
    }
};

class Tiny2Doc : public IXML {
public:
    bool initFrom(const char *filename)
    {
        if (doc.LoadFile(filename)) return false;
        return true;
    }

    INode*  firstNode(const char *name)
    {
        tinyxml2::XMLElement * ele = doc.RootElement();
        root._node = ele->FirstChildElement(name);
        root.name = root._node->Name();
        if (root._node == 0) return 0;
        return &root;
    }
private:
    tinyxml2::XMLDocument doc;
    Tiny2Node root;
};

void initXMLBean(){
    BeanFactory<IXML>::getInstance().addBean("xml",new Tiny2Doc());
}

